
# -----------------------------------------------------------------------------
# calc.py
#
# A simple calculator with variables -- all in one file.
# -----------------------------------------------------------------------------

tokens = (
    'COMMA','NAME','NUMBER',
    'PLUS','MINUS','TIMES','DIVIDE','EQUALS',
    'LPAREN','RPAREN','LSPAREN','RSPAREN',
	'CONS',
    )

# Tokens
t_CONS = r'cons'
t_COMMA = r'\,'
t_PLUS    = r'\+'
t_MINUS   = r'-'
t_TIMES   = r'\*'
t_DIVIDE  = r'/'
t_EQUALS  = r'='
t_LPAREN  = r'\('
t_RPAREN  = r'\)'
t_NAME    = r'[a-zA-Z_][a-zA-Z0-9_]*'
t_LSPAREN = r'\['
t_RSPAREN = r'\]'


def t_NUMBER(t):
    r'\d+'
    try:
        t.value = int(t.value)
    except ValueError:
        print "Integer value too large", t.value
        t.value = 0
    return t

# Ignored characters
t_ignore = " \t"

def t_newline(t):
    r'\n+'
    t.lexer.lineno += t.value.count("\n")
    
def t_error(t):
    print "Illegal character '%s'" % t.value[0]
    t.lexer.skip(1)
    
# Build the lexer
import ply.lex as lex
lex.lex()

# Parsing rules

precedence = (
    ('left','PLUS','MINUS'),
    ('left','TIMES','DIVIDE'),
    ('right','UMINUS'),
    )

# dictionary of names

names = { }
lists = { }


def p_statement_expr(t):
    	'statement : expression'
	print t[1]

def p_expression_list(t):
	'expression : list'	
	t[0] = t[1]

def p_expression_cons(t):
	'expression : cons'
	t[0] = t[1]

def p_expression_liste(t):
	'expression : listelement'
	t[0] = t[1]

def p_statement_assign(t):
    'statement : NAME EQUALS expression'
    names[t[1]] = t[3]


def p_cons(t):
        'cons : CONS LPAREN listelement COMMA list RPAREN'
        t[5] = [ t[3] , t[5] ]
        t[0] = t[5]


def p_expression_binop(t):
    '''expression : expression PLUS expression
                  | expression MINUS expression
                  | expression TIMES expression
                  | expression DIVIDE expression'''
    if t[2] == '+'  : t[0] = t[1] + t[3]
    elif t[2] == '-': t[0] = t[1] - t[3]
    elif t[2] == '*': t[0] = t[1] * t[3]
    elif t[2] == '/': t[0] = t[1] / t[3]




def p_expression_uminus(t):
    'expression : MINUS expression %prec UMINUS'
    t[0] = -t[2]

def p_expression_group(t):
    'expression : LPAREN expression RPAREN'
    t[0] = t[2]

def p_expression_number(t):
    'expression : NUMBER'
    t[0] = t[1]

def p_expression_name(t):
    'expression : NAME'
    try:
        t[0] = names[t[1]]
    except LookupError:
        print "Undefined name '%s'" % t[1]
        t[0] = 0

def p_list(t):
	'list : LSPAREN sequence RSPAREN'
	t[0] =t[2]
	

def p_empty_list(t):
	'list : LPAREN RPAREN'




def p_sequence(t):
    	'''sequence : listelement COMMA sequence
		| listelement'''
	if len(t) == 4 : t[0] = [ t[1] , t[3] ]
	elif len(t) == 2 : t[0]=t[1]



def p_listelement_number(t):
    	'listelement : NUMBER'
	t[0]= t[1]


def p_listelement_list(t):
    	'listelement : list'
	t[0] = t[1]


def p_list_print(t):
	t[0] = "[" + p_seq_print(t[1]) + "]"
	
def p_seq_print(t):
	if isinstance(t[1],listelement) :t[0]= p_liste_print(t)
	else:
		t[0] = p_liste_print(t) + "," + p_seq_print(t)
		

def p_liste_print(t):
	if isinstance(t[1],list) : t[0] = p_list_print(t[1])
	else: t[0] = str(t[1])


def p_error(t):
    print "Syntax error at '%s'" % t.value

import ply.yacc as yacc
yacc.yacc()
index = 0
while 1:
    try:
        s = raw_input('calc > ')
    except EOFError:
        break
    yacc.parse(s)
